package ubadbtools.deadlockAnalyzer.gui.forms;

import java.awt.event.MouseEvent;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;

import javax.swing.DefaultListModel;
import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.LayoutStyle;
import javax.swing.filechooser.FileNameExtensionFilter;

import ubadbtools.deadlockAnalyzer.common.DeadlockModelType;
import ubadbtools.deadlockAnalyzer.common.Schedule;
import ubadbtools.deadlockAnalyzer.gui.controllers.DeadlockAnalyzerFormController;
import ubadbtools.deadlockAnalyzer.gui.etc.ScheduleTableModel;
import ubadbtools.scheduleAnalyzer.common.ScheduleType;
import ubadbtools.util.xml.XMLLib;


/**
* This code was edited or generated using CloudGarden's Jigloo
* SWT/Swing GUI Builder, which is free for non-commercial
* use. If Jigloo is being used commercially (ie, by a corporation,
* company or business for any purpose whatever) then you
* should purchase a license for each developer using Jigloo.
* Please visit www.cloudgarden.com for details.
* Use of Jigloo implies acceptance of these licensing terms.
* A COMMERCIAL LICENSE HAS NOT BEEN PURCHASED FOR
* THIS MACHINE, SO JIGLOO OR THIS CODE CANNOT BE USED
* LEGALLY FOR ANY CORPORATE OR COMMERCIAL PURPOSE.
*/
@SuppressWarnings("serial")
public class DeadlockAnalyzerForm extends JFrame 
{
	/**
	 * Clase con la logica importante del formulario 
	 */
	DeadlockAnalyzerFormController formControl = null;
	File currentFile = null; //Si el archivo fue cargado o guardado, se guarda para ser propuesto ante un nuevo intento de guardar
	DeadlockModelType type;
	
	public JTable getTableSchedule()
	{
		return tableSchedule;
	}
	
	public JList getItemsList()
	{
		return lstItems;
	}
	
    /** Creates new form ScheduleAnalyzerForm */
    public DeadlockAnalyzerForm()
    {
        initComponents();
    }
    
    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    private void initComponents() {//GEN-BEGIN:initComponents

        jScrollPane1 = new javax.swing.JScrollPane();
        tableSchedule = new javax.swing.JTable();
        btnAnalyzeSchedule = new javax.swing.JButton();
        btnAddItem = new javax.swing.JButton();
        btnAddTransaction = new javax.swing.JButton();
        btnAddStep = new javax.swing.JButton();
        jScrollPane2 = new javax.swing.JScrollPane();
        {
        	jPanelInformation = new JPanel();
        }
        {
        	jButtonDetectDeadlock = new JButton();
        	jButtonDetectDeadlock.setText("Detectar Deadlock");
        }
        lstItems = new javax.swing.JList();
        jLabel1 = new javax.swing.JLabel();
        fileMenuBar = new javax.swing.JMenuBar();
        fileMenu = new javax.swing.JMenu();
        NewMenuItem = new javax.swing.JMenuItem();
        LoadMenuItem = new javax.swing.JMenuItem();
        SaveMenuItem = new javax.swing.JMenuItem();
        ExitMenuItem = new javax.swing.JMenuItem();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("Analizador de historias");
        setMinimumSize(new java.awt.Dimension(536, 582));
        setResizable(false);

        tableSchedule.setModel(new ScheduleTableModel());
        tableSchedule.setEnabled(false);
        tableSchedule.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
        tableSchedule.getTableHeader().setResizingAllowed(false);
        tableSchedule.getTableHeader().setReorderingAllowed(false);
        tableSchedule.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                tableScheduleMouseClicked(evt);
            }
        });
        jScrollPane1.setViewportView(tableSchedule);

        btnAnalyzeSchedule.setText("Analizar Historia");
        btnAnalyzeSchedule.setEnabled(false);
        btnAnalyzeSchedule.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                btnAnalyzeScheduleMouseClicked(evt);
            }
        });
        
        jButtonDetectDeadlock.setEnabled(false);
        jButtonDetectDeadlock.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
            	jButtonDetectDeadlockMouseClicked(evt);
            }
        });
        
        btnAddItem.setText("Agregar Item");
        btnAddItem.setEnabled(false);
        btnAddItem.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                btnAddItemMouseClicked(evt);
            }
        });

        btnAddTransaction.setText("Agregar Transacción");
        btnAddTransaction.setEnabled(false);
        btnAddTransaction.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                btnAddTransactionMouseClicked(evt);
            }
        });

        btnAddStep.setText("Agregar Paso");
        btnAddStep.setEnabled(false);
        btnAddStep.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                btnAddStepMouseClicked(evt);
            }
        });

        lstItems.setModel(new DefaultListModel());
        lstItems.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
        lstItems.setEnabled(false);
        lstItems.setLayoutOrientation(javax.swing.JList.HORIZONTAL_WRAP);
        lstItems.setVisibleRowCount(1);
        jScrollPane2.setViewportView(lstItems);

        jLabel1.setText("Items");

        fileMenu.setText("Archivo");

        NewMenuItem.setText("Nuevo");
        NewMenuItem.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mousePressed(java.awt.event.MouseEvent evt) {
                NewMenuItemMouseClicked(evt);
            }
        });
        fileMenu.add(NewMenuItem);

        LoadMenuItem.setText("Cargar");
        LoadMenuItem.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mousePressed(java.awt.event.MouseEvent evt) {
                LoadMenuItemMousePressed(evt);
            }
        });
        fileMenu.add(LoadMenuItem);

        SaveMenuItem.setText("Guardar");
        SaveMenuItem.setEnabled(false);
        SaveMenuItem.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mousePressed(java.awt.event.MouseEvent evt) {
                SaveMenuItemMousePressed(evt);
            }
        });
        fileMenu.add(SaveMenuItem);

        ExitMenuItem.setText("Salir");
        ExitMenuItem.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                ExitMenuItemMouseClicked(evt);
            }
            public void mousePressed(java.awt.event.MouseEvent evt) {
                ExitMenuItemMouseClicked(evt);
            }
        });
        fileMenu.add(ExitMenuItem);

        fileMenuBar.add(fileMenu);

        setJMenuBar(fileMenuBar);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setVerticalGroup(layout.createSequentialGroup()
        	.addGap(7)
        	.addGroup(layout.createParallelGroup()
        	    .addGroup(layout.createSequentialGroup()
        	        .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
        	            .addComponent(btnAddTransaction, GroupLayout.Alignment.BASELINE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
        	            .addComponent(btnAddItem, GroupLayout.Alignment.BASELINE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
        	            .addComponent(jButtonDetectDeadlock, GroupLayout.Alignment.BASELINE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE))
        	        .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
        	        .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
        	            .addComponent(btnAddStep, GroupLayout.Alignment.BASELINE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
        	            .addComponent(btnAnalyzeSchedule, GroupLayout.Alignment.BASELINE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)))
        	    .addComponent(jPanelInformation, GroupLayout.Alignment.LEADING, 0, 48, Short.MAX_VALUE))
        	.addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
        	.addComponent(jScrollPane1, GroupLayout.PREFERRED_SIZE, 339, GroupLayout.PREFERRED_SIZE)
        	.addGap(17)
        	.addComponent(jLabel1, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
        	.addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
        	.addComponent(jScrollPane2, GroupLayout.PREFERRED_SIZE, 37, GroupLayout.PREFERRED_SIZE)
        	.addContainerGap(46, 46));
        layout.setHorizontalGroup(layout.createSequentialGroup()
        	.addContainerGap()
        	.addGroup(layout.createParallelGroup()
        	    .addGroup(GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
        	        .addGroup(layout.createParallelGroup()
        	            .addComponent(btnAddStep, GroupLayout.Alignment.LEADING, GroupLayout.PREFERRED_SIZE, 366, GroupLayout.PREFERRED_SIZE)
        	            .addGroup(GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
        	                .addGroup(layout.createParallelGroup()
        	                    .addComponent(btnAddTransaction, GroupLayout.Alignment.LEADING, GroupLayout.PREFERRED_SIZE, 230, GroupLayout.PREFERRED_SIZE)
        	                    .addGroup(GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
        	                        .addComponent(jLabel1, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
        	                        .addGap(199)))
        	                .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
        	                .addComponent(btnAddItem, GroupLayout.PREFERRED_SIZE, 131, GroupLayout.PREFERRED_SIZE)))
        	        .addComponent(jPanelInformation, 0, 44, Short.MAX_VALUE)
        	        .addGroup(layout.createParallelGroup()
        	            .addGroup(layout.createSequentialGroup()
        	                .addComponent(btnAnalyzeSchedule, GroupLayout.PREFERRED_SIZE, 181, GroupLayout.PREFERRED_SIZE)
        	                .addGap(0, 0, Short.MAX_VALUE))
        	            .addComponent(jButtonDetectDeadlock, GroupLayout.Alignment.LEADING, 0, 182, Short.MAX_VALUE)))
        	    .addComponent(jScrollPane1, GroupLayout.Alignment.LEADING, 0, 592, Short.MAX_VALUE)
        	    .addComponent(jScrollPane2, GroupLayout.Alignment.LEADING, 0, 592, Short.MAX_VALUE))
        	.addContainerGap());

        pack();
    }//GEN-END:initComponents

    private void ExitMenuItemMouseClicked(java.awt.event.MouseEvent evt)
    {//GEN-FIRST:event_ExitMenuItemMouseClicked
    	System.exit(0);
    }//GEN-LAST:event_ExitMenuItemMouseClicked

    private void btnAddTransactionMouseClicked(java.awt.event.MouseEvent evt)
    {//GEN-FIRST:event_btnAddTransactionMouseClicked
    	if(btnAddTransaction.isEnabled())
    	{
	    	try
			{
				formControl.AddNewTransaction();
			}
			catch (Exception ex)
			{
				ShowErrorMessage("Ocurrio un error al agregar la nueva transacci�n: " + ex.getMessage());
			}
    	}
    }//GEN-LAST:event_btnAddTransactionMouseClicked

    private void btnAddStepMouseClicked(java.awt.event.MouseEvent evt)
    {//GEN-FIRST:event_btnAddStepMouseClicked
    	if(btnAddStep.isEnabled())
    	{
	    	try
			{
				formControl.AddNewStep();
			}
			catch (Exception ex)
			{
				ShowErrorMessage(ex.getMessage());
			}
    	}
    }//GEN-LAST:event_btnAddStepMouseClicked

	private void btnAnalyzeScheduleMouseClicked(java.awt.event.MouseEvent evt)
    {//GEN-FIRST:event_btnAnalyzeScheduleMouseClicked
        if(btnAnalyzeSchedule.isEnabled())
        {
        	formControl.AnalyzeSchedule();
        }
    }//GEN-LAST:event_btnAnalyzeScheduleMouseClicked
	
	private void jButtonDetectDeadlockMouseClicked(MouseEvent evt)
	{
		if(jButtonDetectDeadlock.isEnabled())
        {
        	formControl.DeadLockDetectSchedule();
        }
		
	}

    private void btnAddItemMouseClicked(java.awt.event.MouseEvent evt)
    {//GEN-FIRST:event_btnAddItemMouseClicked
    	if(btnAddItem.isEnabled())
    	{
	    	try
			{
				formControl.AddNewItem();
			}
			catch (Exception ex)
			{
				ShowErrorMessage("Ocurrió un error al agregar el nuevo ítem: " + ex.getMessage());
			}
    	}
    }//GEN-LAST:event_btnAddItemMouseClicked

    private void NewMenuItemMouseClicked(java.awt.event.MouseEvent evt)
    {//GEN-FIRST:event_NewMenuItemMouseClicked
        // Invoco al dialogo para elegir el tipo de historia y la guardo en el control
    	type = SelectDeadlockModelTypeDialog.showDialog(this);

        // Creo el control y lo inicializo
        formControl = DeadlockAnalyzerFormController.CreateController(this, type);
   
        // Por �ltimo, pongo en null al archivo cargado indicando que es un nuevo schedule
        currentFile = null;
    }//GEN-LAST:event_NewMenuItemMouseClicked

    /**
     * Habilita los controles que interactuan con el usuario
     */
	public void EnableUserControls()
	{
		btnAddItem.setEnabled(true);
		btnAddStep.setEnabled(true);
		btnAddTransaction.setEnabled(true);
        btnAnalyzeSchedule.setEnabled(true);
        tableSchedule.setEnabled(true);
        lstItems.setEnabled(true);
        SaveMenuItem.setEnabled(true);
        if (type == DeadlockModelType.DETECTION)
        	jButtonDetectDeadlock.setEnabled(true);
        else
        	jButtonDetectDeadlock.setEnabled(false);
	}

    private void LoadMenuItemMousePressed(java.awt.event.MouseEvent evt)
    {//GEN-FIRST:event_LoadMenuItemMousePressed
    	JFileChooser fileChooser = new JFileChooser();

	    //S�lo permito que se agreguen .xml
    	fileChooser.addChoosableFileFilter(new FileNameExtensionFilter("XML file", "xml"));
        fileChooser.setAcceptAllFileFilterUsed(false);

        //Muestro el dialog
        int dialogResult = fileChooser.showDialog(this,"Cargar");

        //Si seleccionaron alg�n archivo...
        if (dialogResult == JFileChooser.APPROVE_OPTION) 
        {
            File file = fileChooser.getSelectedFile();
            try
            {
            	//Cargo el schedule a partir del XML
            	this.LoadScheduleFromFile(file);
            }
            catch(Exception ex)
            {
            	ShowErrorMessage("Ocurrió un error al cargar la historia: " + ex.getMessage());
            }
            
            //Me guardo el archivo cargado as� cuando quieren guardar ya tienen todo
            currentFile = file;
        }
    }//GEN-LAST:event_LoadMenuItemMousePressed

	private void SaveMenuItemMousePressed(java.awt.event.MouseEvent evt)
	{//GEN-FIRST:event_SaveMenuItemMousePressed
		if(SaveMenuItem.isEnabled())
		{
			JFileChooser fileChooser = new JFileChooser();
	
		    //S�lo permito que se agreguen .xml
	    	fileChooser.addChoosableFileFilter(new FileNameExtensionFilter("XML file", "xml"));
	        fileChooser.setAcceptAllFileFilterUsed(false);
	
	        //Si el schedule fue cargado, propongo guardar el mismo archivo
	        if(currentFile != null)
	        	fileChooser.setCurrentDirectory(currentFile);
	        
	        //Muestro el dialog
	        int dialogResult = fileChooser.showDialog(this, "Guardar");
	
	        //Si seleccionaron alg�n archivo...
	        if (dialogResult == JFileChooser.APPROVE_OPTION) 
	        {
	            File file = fileChooser.getSelectedFile();
	            
	            // Si el archivo no tiene extension, se la agrego
	            if(file.getName().indexOf(".") == -1)
	            {
	            	file = new File(file.getAbsolutePath() + ".xml");
	            }
	            
	            try
	            {
	            	//Guardo el schedule en formato XML
	            	this.SaveScheduleToFile(file);
	            }
	            catch(Exception ex)
	            {
	            	ShowErrorMessage("Ocurrió un error al guardar la historia: " + ex.getMessage());
	            }
	            
	            //Me guardo el path del archivo as� cuando quieren guardar ya tienen todo
	            currentFile = file;
	        }
		}		
    }//GEN-LAST:event_SaveMenuItemMousePressed

    private void tableScheduleMouseClicked(java.awt.event.MouseEvent evt)
    {//GEN-FIRST:event_tableScheduleMouseClicked
        if(tableSchedule.isEnabled())
        {
	    	// Verifico si hubo un doble click
	    	if(evt.getClickCount() == 2)
	        {
	        	// Lanzo el editor de paso para el paso sobre la que se hizo doble click en la tabla
	    		try
				{
					formControl.EditRecord(tableSchedule.getSelectedRow());
				}
				catch (Exception ex)
				{
					ShowErrorMessage("Ocurrio un error al editar el paso: " + ex.getMessage());
				}
	        }
        }
    }//GEN-LAST:event_tableScheduleMouseClicked

    
    /**
	 * Carga una historia desde el archivo dado
	 * @param file
	 * @throws ScheduleException 
	 */
	private void LoadScheduleFromFile(File file) throws Exception
	{
		 // Genero la historia desde el archivo
		Schedule schedule = null;
		try
		{
			schedule = (Schedule)XMLLib.fromXML(new FileReader(file));
		}
		catch(Exception e)
		{
			throw new Exception("La historia que se quiere cargar está malformada (" + e.getMessage() + ")");
		}
		
		// Genero un nuevo controlador para la nueva historia
		type = schedule.getDeadlockModelType();
		schedule.fillTimestamps();
		formControl = DeadlockAnalyzerFormController.CreateController(this, schedule);
	}
	
	 /**
	  * Guarda la historia en el archivo dado
	  * @param file
	  * @throws ScheduleException 
	  */
	private void SaveScheduleToFile(File file) throws Exception
	{
		// Obtengo la historia desde el controlador
		Schedule schedule = formControl.GetSchedule();
		 
		try
		{
			XMLLib.toXML(schedule,new FileWriter(file));
		}
		catch(Exception e)
		{
			throw new Exception("La historia que se quiere guardar es inválida (" + e.getMessage() + ")");
		}
	}
	
	
	/**
     * Muestra un mensaje de error al usuario
     * @param message
     */
	public void ShowErrorMessage(String message)
	{
		JOptionPane.showConfirmDialog(
			this,
			message,
			"Error",
			JOptionPane.DEFAULT_OPTION,
			JOptionPane.ERROR_MESSAGE);
	}
    
	/**
	 * Muestra un mensaje con un campo para que el usuario ingrese texto
	 * @param message
	 * @return
	 */
	public String ShowInputDialog(String message)
	{
		String ret;
		
		// Si no se agrego ningun texto, vuelvo a preguntar
		do
		{
			 ret = JOptionPane.showInputDialog(this, message);
		}
		while(ret != null && ret.equals(""));
		
		return ret; 
	}
	
	
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JMenuItem ExitMenuItem;
    private javax.swing.JMenuItem LoadMenuItem;
    private javax.swing.JMenuItem NewMenuItem;
    private javax.swing.JMenuItem SaveMenuItem;
    private javax.swing.JButton btnAddItem;
    private javax.swing.JButton btnAddStep;
    private javax.swing.JButton btnAddTransaction;
    private javax.swing.JButton btnAnalyzeSchedule;
    private javax.swing.JMenu fileMenu;
    private javax.swing.JMenuBar fileMenuBar;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private JPanel jPanelInformation;
    private JButton jButtonDetectDeadlock;
    private javax.swing.JList lstItems;
    private javax.swing.JTable tableSchedule;
    // End of variables declaration//GEN-END:variables
}
